package com.googlecode.alfrescocachingserver.model;

import java.io.Serializable;
import java.util.Arrays;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.lang3.StringUtils;
import org.springframework.extensions.webscripts.connector.HttpMethod;

public class WebScriptUri implements Serializable
{
    private static final long serialVersionUID = -45401369929044515L;

    private static final Pattern PATTERN_WEB_SCRIPT_URI = Pattern
            .compile(".*?/(alfresco)(?:/service|/s)?(/?[^\\?$;]*)(?:;jsessionid=[^\\?$]*)?(?:\\?(.*))?$");

    protected String endpoint;
    protected HttpMethod httpMethod;
    protected String uri;
    protected String queryString;
    protected String uriWithQueryString;

    public WebScriptUri(final HttpServletRequest request)
    {
        this(request.getMethod(), request.getRequestURI(), request.getQueryString());
    }

    public WebScriptUri(final String httpMethod, final String uri)
    {
        this(httpMethod, uri, null);
    }

    public WebScriptUri(final String httpMethod, final String uri, final String queryString)
    {
        setHttpMethod(httpMethod);
        parseUri(uri);
        
        if (queryString != null)
        {
            setQueryString(queryString);
        }
        
        setUriWithQueryString();
    }

    // public WebScriptUri(final String httpMethod, final String endpoint, final
    // String uri, final String queryString)
    // {
    // setHttpMethod(httpMethod);
    // setEndpoint(endpoint);
    // parseUri(uri);
    // setQueryString(queryString);
    // setUriWithQueryString();
    // }

    public String getEndpoint()
    {
        return endpoint;
    }

    protected void setEndpoint(final String endpoint)
    {
        this.endpoint = endpoint;
    }

    public HttpMethod getHttpMethod()
    {
        return httpMethod;
    }

    protected void setHttpMethod(HttpMethod httpMethod)
    {
        this.httpMethod = httpMethod;
    }

    protected void setHttpMethod(String httpMethod)
    {
        HttpMethod httpMethodEnum = HttpMethod.valueOf(httpMethod);

        this.httpMethod = httpMethodEnum;
    }

    public String getUri()
    {
        return uri;
    }

    protected void setUri(final String uri)
    {
        if (StringUtils.isNotBlank(uri))
        {
            this.uri = uri.trim();
        }
        else
        {
            this.uri = "/";
        }
    }

    public String getUriWithQueryString()
    {
        return uriWithQueryString;
    }

    protected void setUriWithQueryString()
    {
        StringBuilder buf = new StringBuilder(uri);

        if (queryString != null)
        {
            buf.append("?").append(queryString);
        }

        this.uriWithQueryString = buf.toString();
    }

    public String getQueryString()
    {
        return queryString;
    }

    protected void setQueryString(final String queryString)
    {
        if (StringUtils.isNotBlank(queryString))
        {
            StringBuilder buf = new StringBuilder();

            String[] queryStrNvps = queryString.split("&");
            Arrays.sort(queryStrNvps);

            for (String nameValuePair : queryStrNvps)
            {
//                String[] nameValue = nvp.split("=");
//
//                String paramName = nameValue[0];
//                String paramValue = nameValue[1];
//
//                if (paramValue == null)
//                    paramValue = StringUtils.EMPTY;
//
//                buf.append(paramName).append("=").append(paramValue).append("&");
                
                buf.append(nameValuePair).append("&");
            }

            if (buf.length() > 0)
            {
                // remove the last ampersand
                buf.deleteCharAt(buf.length() - 1);
            }

            this.queryString = buf.toString();
        }
        else
        {
            this.queryString = null;
        }
    }

    @Override
    public int hashCode()
    {
        final int prime = 31;
        int result = 1;
        result = prime * result + ((endpoint == null) ? 0 : endpoint.hashCode());
        result = prime * result + ((httpMethod == null) ? 0 : httpMethod.hashCode());
        result = prime * result + ((queryString == null) ? 0 : queryString.hashCode());
        result = prime * result + ((uri == null) ? 0 : uri.hashCode());
        return result;
    }

    @Override
    public boolean equals(Object obj)
    {
        if (this == obj)
            return true;
        
        if (obj == null)
            return false;
        
        if (getClass() != obj.getClass())
            return false;
        
        WebScriptUri other = (WebScriptUri) obj;
        if (endpoint == null)
        {
            if (other.endpoint != null)
                return false;
        }
        else if (!endpoint.equals(other.endpoint))
            return false;
        
        if (httpMethod != other.httpMethod)
            return false;
        
        if (queryString == null)
        {
            if (other.queryString != null)
                return false;
        }
        else if (!queryString.equals(other.queryString))
            return false;
        
        if (uri == null)
        {
            if (other.uri != null)
                return false;
        }
        else if (!uri.equals(other.uri))
            return false;
        
        return true;
    }

    private void parseUri(final String uri)
    {
        Matcher matcher = PATTERN_WEB_SCRIPT_URI.matcher(uri);

        if (matcher.matches())
        {
            setEndpoint(matcher.group(1));

            if (matcher.groupCount() > 1)
            {
                setUri(matcher.group(2));
            }

            if (matcher.groupCount() > 2)
            {
                setQueryString(matcher.group(3));
            }
        }
        else
        {
            throw new RuntimeException("Invalid webscript URI:  " + uri);
        }
    }
}
